using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WenYu.Core.Lexer;

/// <summary>
/// 文语词法分析器
/// 支持清晰风格和紧凑风格（无空格）
/// </summary>
public class WenYuLexer
{
    private readonly string _source;
    private readonly ReadOnlyMemory<char> _sourceMemory;
    private int _position;
    private int _line;
    private int _column;
    
    // 关键字Trie树（静态共享）
    private static readonly KeywordTrie _keywordTrie;
    private static readonly HashSet<string> _keywords;
    private static readonly HashSet<string> _typeKeywords;
    private static readonly HashSet<string> _arrayTypeKeywords;
    private static readonly HashSet<string> _comparisonOperatorKeywords;
    
    /// <summary>
    /// 独立关键字集合：紧凑风格中必须单独识别的关键字
    /// 例如："整型组" 应该被识别为 "整型" + "组"（两个token）
    /// </summary>
    private static readonly HashSet<string> _independentKeywords;
    
    /// <summary>
    /// 可合并关键字集合：这些单字关键字在后面跟汉字时，优先作为标识符的一部分
    /// 例如："步长" 应该被识别为一个标识符，而不是 "步" + "长"
    /// </summary>
    private static readonly HashSet<string> _mergeableKeywords;
    
    // 明显边界字符
    private static readonly HashSet<char> _explicitBoundaries = new()
    {
        ' ', '\t', '\n', '\r',                    // 空白
        '。', '.', '，', ',',                      // 标点
        '（', '）', '(', ')',                      // 圆括号
        '{', '}', '【', '】', '[', ']',           // 方括号和大括号
        '+', '-', '*', '÷', '/', '%',             // 算术运算符
        '》', '《',                                // 比较运算符
        '且', '或', '不',                          // 逻辑运算符
        ';', ':', '!', '?', '=',                  // 其他符号
        '·',                                      // 间隔号
        '"', '\u201C', '\u201D',                  // 引号（英文双引号、英文全角左右引号）
        '\0'                                      // 文件结束
    };
    
    static WenYuLexer()
    {
        // ===== 关键字分类说明 =====
        // 1. _keywords: 通用关键字（控制流、函数、类、逻辑运算）
        // 2. _typeKeywords: 类型关键字（基本类型、维度前缀、数组构造器）
        // 3. _arrayTypeKeywords: 预定义数组类型（兼容性保留，实际会被拆分）
        
        // 初始化通用关键字列表 (29个)
        _keywords = new HashSet<string>
        {
            // 控制流 (12个)
            "若", "则", "余", "又",
            "复", "至", "从", "步", "几", "取", "续",
            "停", "跳",
            // 函数 (5个)
            "求", "法", "之", "得", "回",
            // 类与对象 (2个)
            "类", "含",
            // 赋值和属性 (3个)
            "是", "设", "的",
            // 真假值 (2个)
            "真真", "假假",
            // 比较运算符（汉字形式） (4个)
            // 注意："不大于"、"不小于"通过组合"不"+"大于/小于"实现
            "同", "不同", "大于", "小于"
        };
        
        // 初始化类型关键字列表 (14个)
        _typeKeywords = new HashSet<string>
        {
            // 基本类型 (4个)
            "整型", "实型", "文字", "真假",
            
            // 数组维度关键字 (9个) - 用于多维数组声明
            "一维", "二维", "三维", "四维", "五维", 
            "六维", "七维", "八维", "九维",
            
            // 数组类型构造器 (1个) - 用于构造数组类型
            // 示例: 整型组、车组、二维整型组
            "组"
        };
        
        // 初始化预定义数组类型 (4个) - 兼容性保留
        // 注意: 实际会被Trie树拆分为 "整型"+"组" 等
        _arrayTypeKeywords = new HashSet<string>
        {
            "整型组", "实型组", "文字组", "真假组"
        };
        
        _comparisonOperatorKeywords = new HashSet<string>
        {
            "大于", "小于", "同", "不同"
        };
        
        // 初始化独立关键字集合
        // 注意：这里采用双重策略
        // 1. _independentKeywords: 紧凑风格中必须独立的关键字（如"组"、"的"）
        // 2. _mergeableKeywords: 可以与后续汉字合并为标识符的单字关键字（如"步"）
        _independentKeywords = new HashSet<string>
        {
            "的",  // 成员访问运算符：宝马的价格（紧凑风格）
            // 注意：不包含"组"，允许其作为标识符的一部分（如"数组"、"组长"）
            // "组"在类型后面时由Parser识别为数组构造器（如"整型组"）
        };
        
        // 可合并关键字：这些单字关键字在后面跟汉字时，优先作为标识符的一部分
        // 例如："步长"应识别为标识符，而不是"步" + "长"
        // 注意：这些关键字通常在实际使用时会有空格分隔
        _mergeableKeywords = new HashSet<string>
        {
            "步",  // for循环步长：复 i 从 1 至 3 步 1（有空格时是关键字）
                  // 但"步长"作为变量名时应识别为完整标识符
            "复",  // for循环：复 i 从 1 至 10（有空格时是关键字）
                  // 但"复杂"作为变量名时应识别为完整标识符
            // "取" - 移除，因为"取值"、"取货"等不太可能作为变量名
            //        在紧凑风格中，"取"应该总是独立识别（foreach关键字）
            "余",  // else子句：若...则...余...（有空格时是关键字）
                  // 但"余数"、"余额"作为变量名时应识别为完整标识符
            "是",  // 赋值关键字：甲 是 10（有空格时是关键字）
                  // 但"是非"作为变量名时应识别为完整标识符
        };
        
        // 构建Trie树
        _keywordTrie = new KeywordTrie();
        foreach (var keyword in _keywords)
        {
            _keywordTrie.Insert(keyword);
        }
        foreach (var keyword in _typeKeywords)
        {
            _keywordTrie.Insert(keyword);
        }
        // ❌ 不要添加预定义数组类型到Trie树，因为这会导致FMM优先匹配"整型组"而不是"整型"+"组"
        // 这些组合应该由Parser处理，而不是Lexer
        // foreach (var keyword in _arrayTypeKeywords)
        // {
        //     _keywordTrie.Insert(keyword);
        // }
    }
    
    public WenYuLexer(string source)
    {
        _source = source ?? throw new ArgumentNullException(nameof(source));
        _sourceMemory = _source.AsMemory();
        _position = 0;
        _line = 1;
        _column = 1;
    }
    
    /// <summary>
    /// 优化2: 内联边界检查方法（避免HashSet查找开销）
    /// </summary>
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    private static bool IsBoundary(char ch)
    {
        return _explicitBoundaries.Contains(ch);
    }
    
    /// <summary>
    /// 优化1: 使用Span创建字符串（减少内存分配）
    /// </summary>
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    private string GetSubstring(int start, int length)
    {
        return _sourceMemory.Slice(start, length).ToString();
    }
    
    /// <summary>
    /// 对源代码进行完整的词法分析
    /// </summary>
    public List<Token> Tokenize()
    {
        var tokens = new List<Token>();
        
        while (!IsAtEnd())
        {
            var token = ScanToken();
            if (token != null && token.Type != TokenType.Comment)
            {
                tokens.Add(token);
            }
        }
        
        // 添加EOF标记
        tokens.Add(new Token(TokenType.EOF, "", _line, _column, _position));
        
        return tokens;
    }
    
    /// <summary>
    /// 扫描下一个Token
    /// </summary>
    private Token? ScanToken()
    {
        SkipWhitespace();
        
        if (IsAtEnd())
            return null;
        
        int startLine = _line;
        int startColumn = _column;
        int startPosition = _position;
        
        char current = Peek();
        
        // 注释
        if (current == '—' && PeekNext() == '—')
        {
            return ScanComment();
        }
        
        // 数字
        if (char.IsDigit(current))
        {
            return ScanNumber();
        }
        
        // 字符串（支持中英文引号）
        if (current == '"' || current == '\u201C' || current == '\u201D')
        {
            return ScanString();
        }
        
        // 运算符和标点符号
        if (IsBoundary(current))
        {
            return ScanOperatorOrPunctuation();
        }
        
        // 关键字或标识符（包括汉字）
        if (IsIdentifierStart(current))
        {
            return ScanIdentifierOrKeyword();
        }
        
        // 无法识别的字符
        Advance();
        return new Token(TokenType.Error, current.ToString(), startLine, startColumn, startPosition);
    }
    
    /// <summary>
    /// 扫描标识符或关键字（核心算法：正向最大匹配）
    /// </summary>
    private Token ScanIdentifierOrKeyword()
    {
        int startLine = _line;
        int startColumn = _column;
        int startPosition = _position;
        
        // 使用Trie树查找最长关键字
        var (keyword, keywordLength) = _keywordTrie.FindLongestMatch(_source, _position);
        
        if (keyword != null)
        {
            // 找到了关键字，检查后面是什么
            int afterKeywordPos = _position + keywordLength;
            
            // 情况1：到达文件结尾
            if (afterKeywordPos >= _source.Length)
            {
                AdvanceBy(keywordLength);
                return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
            }
            
            char nextChar = _source[afterKeywordPos];
            
            // 情况2：后面是明显边界
            if (IsBoundary(nextChar))
            {
                AdvanceBy(keywordLength);
                return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
            }
            
            // 情况3：后面是数字
            // 关键字后面跟数字时，应该独立识别关键字（如"步1"应该分成"步"和"1"）
            // 注意：_mergeableKeywords只适用于"关键字+汉字"的情况，不适用于"关键字+数字"
            if (char.IsDigit(nextChar))
            {
                AdvanceBy(keywordLength);
                return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
            }
            
            // 情况4：后面是英文字母（在紧凑风格中，关键字应该独立识别）
            // 例如："复i" 应该分成 "复" + "i"，而不是识别为一个标识符"复i"
            if (char.IsLetter(nextChar) && !IsCJKChar(nextChar))
            {
                // 单字关键字后跟英文字母，应该独立识别关键字
                AdvanceBy(keywordLength);
                return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
            }
            
            // 情况5：后面还有汉字，需要进一步判断
            // 检查"关键字+后续"是否能形成更长的关键字
            if (IsCJKChar(nextChar))
            {
                // 对于单字关键字，需要判断是否可以与后续字符合并
                if (keywordLength == 1)
                {
                    // 情况A：独立关键字必须单独识别（如"组"、"的"）
                    if (_independentKeywords.Contains(keyword))
                    {
                        AdvanceBy(keywordLength);
                        return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
                    }
                    
                    // 情况B：可合并关键字可以作为标识符的一部分（如"步"）
                    if (_mergeableKeywords.Contains(keyword))
                    {
                        // 不返回，继续往下执行，让它进入标识符扫描逻辑
                        // 这样"步长"会被识别为一个完整标识符
                    }
                    else
                    {
                        // 情况C：其他单字关键字默认独立识别（如"若"、"是"、"回"等）
                        AdvanceBy(keywordLength);
                        return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
                    }
                }
                else
                {
                    // 对于多字关键字，向前看寻找边界
                    int lookAheadPos = afterKeywordPos;
                    while (lookAheadPos < _source.Length)
                    {
                        char lookAheadChar = _source[lookAheadPos];
                        
                        if (IsBoundary(lookAheadChar) || char.IsDigit(lookAheadChar))
                        {
                            // 找到边界，确认当前关键字
                            AdvanceBy(keywordLength);
                            return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
                        }
                        
                        // 检查是否是关键字开始
                        if (_keywordTrie.Root.Children.ContainsKey(lookAheadChar))
                        {
                            // 可能是关键字开始，确认当前关键字
                            AdvanceBy(keywordLength);
                            return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
                        }
                        
                        lookAheadPos++;
                    }
                    
                    // 到达末尾，确认为关键字
                    AdvanceBy(keywordLength);
                    return CreateKeywordToken(keyword, startLine, startColumn, startPosition);
                }
            }
        }
        
        // 没有匹配到关键字，扫描标识符
        var identifier = new StringBuilder();
        while (!IsAtEnd())
        {
            char ch = Peek();
            
            // 遇到边界，停止
            if (IsBoundary(ch))
            {
                break;
            }
            
            // 允许数字作为标识符的一部分（如结果1、变量2），但标识符必须已经有内容
            if (char.IsDigit(ch))
            {
                if (identifier.Length == 0)
                {
                    // 不能以数字开头
                    break;
                }
                else
                {
                    // 标识符已有内容，可以追加数字
                    identifier.Append(Advance());
                    continue;
                }
            }
            
            // 检查是否遇到关键字（多字关键字优先）
            if (identifier.Length > 0)
            {
                var (possibleKeyword, keywordLen) = _keywordTrie.FindLongestMatch(_source, _position);
                if (possibleKeyword != null && keywordLen > 1)
                {
                    // 找到多字关键字（如"大于"、"整型"等），结束当前标识符
                    break;
                }
                else if (possibleKeyword != null && keywordLen == 1)
                {
                    // 找到单字关键字，需要更谨慎判断
                    int afterPos = _position + 1;
                    
                    if (afterPos >= _source.Length)
                    {
                        // 到达末尾，确认为关键字
                        break;
                    }
                    
                    char afterChar = _source[afterPos];
                    
                    // 如果后面有明显边界或数字，确认为关键字
                    if (IsBoundary(afterChar) || char.IsDigit(afterChar))
                    {
                        break;
                    }
                    
                    // 如果后面不是CJK字符，也确认为关键字
                    if (!IsCJKChar(afterChar) && !char.IsLetter(afterChar) && afterChar != '_')
                    {
                        break;
                    }
                    
                    // 特殊处理：独立关键字必须作为单独的token，不能作为标识符的一部分
                    if (_independentKeywords.Contains(possibleKeyword))
                    {
                        break;
                    }
                    
                    // 检查后面是否是另一个关键字的开始
                    if (_keywordTrie.Root.Children.ContainsKey(afterChar))
                    {
                        // 后面可能是关键字，确认当前单字关键字
                        break;
                    }
                    
                    // 可合并关键字可以作为标识符的一部分（如"余数"中的"余"），继续扫描
                    if (_mergeableKeywords.Contains(possibleKeyword))
                    {
                        // 继续扫描，作为标识符的一部分
                        // 例如："余数"会被识别为一个完整标识符
                    }
                    else
                    {
                        // 默认情况：单字关键字应该独立识别，不作为标识符的一部分
                        // 例如："复列表取项"中的"取"应该独立识别
                        break;
                    }
                }
            }
            
            identifier.Append(Advance());
        }
        
        return new Token(TokenType.Identifier, identifier.ToString(), startLine, startColumn, startPosition);
    }
    
    /// <summary>
    /// 创建关键字Token
    /// </summary>
    private Token CreateKeywordToken(string keyword, int line, int column, int position)
    {
        TokenType type;
        if (_typeKeywords.Contains(keyword))
        {
            type = TokenType.TypeKeyword;
        }
        else if (_arrayTypeKeywords.Contains(keyword))
        {
            type = TokenType.ArrayTypeKeyword;
        }
        else if (keyword == "真真" || keyword == "假假")
        {
            type = TokenType.BooleanLiteral;
        }
        else if (_comparisonOperatorKeywords.Contains(keyword))
        {
            type = TokenType.ComparisonOperator;
        }
        else
        {
            type = TokenType.Keyword;
        }
        
        return new Token(type, keyword, line, column, position);
    }
    
    /// <summary>
    /// 扫描数字（整数或实数）
    /// </summary>
    private Token ScanNumber()
    {
        int startLine = _line;
        int startColumn = _column;
        int startPosition = _position;
        
        var number = new StringBuilder();
        bool isDouble = false;
        
        // 扫描整数部分
        while (!IsAtEnd() && char.IsDigit(Peek()))
        {
            number.Append(Advance());
        }
        
        // 检查小数点
        if (!IsAtEnd() && Peek() == '.' && PeekNext() != '\0' && char.IsDigit(PeekNext()))
        {
            isDouble = true;
            number.Append(Advance()); // 消耗 '.'
            
            // 扫描小数部分
            while (!IsAtEnd() && char.IsDigit(Peek()))
            {
                number.Append(Advance());
            }
        }
        
        TokenType type = isDouble ? TokenType.DoubleLiteral : TokenType.IntegerLiteral;
        return new Token(type, number.ToString(), startLine, startColumn, startPosition);
    }
    
    /// <summary>
    /// 扫描字符串
    /// </summary>
    private Token ScanString()
    {
        int startLine = _line;
        int startColumn = _column;
        int startPosition = _position;
        
        char openQuote = Advance(); // 消耗开始引号
        
        // 确定闭合引号（支持成对的中英文引号）
        char closeQuote = openQuote switch
        {
            '"' => '"',             // 英文双引号 (U+0022)
            '\u201C' => '\u201D',   // 英文全角左双引号 → 右双引号
            _   => openQuote        // 默认：使用相同的引号
        };
        
        var content = new StringBuilder();
        
        while (!IsAtEnd() && Peek() != closeQuote)
        {
            if (Peek() == '\\' && _position + 1 < _source.Length)
            {
                Advance();
                char escaped = Advance();
                content.Append(escaped switch
                {
                    'n' => '\n',
                    't' => '\t',
                    'r' => '\r',
                    '\\' => '\\',
                    '"' => '"',  // 英文引号
                    _ => escaped
                });
            }
            else
            {
                content.Append(Advance());
            }
        }
        
        if (IsAtEnd())
        {
            // 字符串未闭合
            return new Token(TokenType.Error, "未闭合的字符串", startLine, startColumn, startPosition);
        }
        
        Advance(); // 消耗结束引号
        
        return new Token(TokenType.StringLiteral, content.ToString(), startLine, startColumn, startPosition);
    }
    
    /// <summary>
    /// 扫描运算符或标点符号
    /// </summary>
    private Token ScanOperatorOrPunctuation()
    {
        int startLine = _line;
        int startColumn = _column;
        int startPosition = _position;
        
        char current = Advance();
        string value = current.ToString();
        TokenType type;
        
        // 检查双字符运算符
        if (!IsAtEnd())
        {
            char next = Peek();
            string twoChar = value + next;
            
            if (twoChar == "++" || twoChar == "--" || twoChar == "不同" || twoChar == "不《" || twoChar == "不》")
            {
                Advance();
                value = twoChar;
            }
        }
        
        // 确定Token类型
        type = value switch
        {
            "》" or "《" or "不《" or "不》" or "不同" => TokenType.ComparisonOperator,
            "且" or "或" or "不" => TokenType.LogicalOperator,
            "+" or "-" or "*" or "÷" or "/" or "%" or "++" or "--" => TokenType.Operator,
            _ => TokenType.Punctuation
        };
        
        return new Token(type, value, startLine, startColumn, startPosition);
    }
    
    /// <summary>
    /// 扫描注释
    /// </summary>
    private Token ScanComment()
    {
        int startLine = _line;
        int startColumn = _column;
        int startPosition = _position;
        
        // 跳过 ——
        Advance();
        Advance();
        
        var content = new StringBuilder();
        while (!IsAtEnd() && Peek() != '\n')
        {
            content.Append(Advance());
        }
        
        return new Token(TokenType.Comment, content.ToString(), startLine, startColumn, startPosition);
    }
    
    // ===== 辅助方法 =====
    
    private void SkipWhitespace()
    {
        while (!IsAtEnd())
        {
            char c = Peek();
            if (c == ' ' || c == '\t' || c == '\r')
            {
                Advance();
            }
            else if (c == '\n')
            {
                Advance();
                _line++;
                _column = 1;
            }
            else
            {
                break;
            }
        }
    }
    
    private bool IsAtEnd() => _position >= _source.Length;
    
    private char Peek() => IsAtEnd() ? '\0' : _source[_position];
    
    private char PeekNext() => _position + 1 >= _source.Length ? '\0' : _source[_position + 1];
    
    private char Advance()
    {
        char c = _source[_position];
        _position++;
        _column++;
        return c;
    }
    
    private void AdvanceBy(int count)
    {
        for (int i = 0; i < count; i++)
        {
            Advance();
        }
    }
    
    private bool IsIdentifierStart(char c)
    {
        return char.IsLetter(c) || c == '_' || IsCJKChar(c);
    }
    
    private bool IsCJKChar(char c)
    {
        return c >= 0x4E00 && c <= 0x9FFF; // 中日韩统一表意文字
    }
    
    /// <summary>
    /// 判断词是否为关键字（供外部使用，如IDE）
    /// </summary>
    public static bool IsKeyword(string word)
    {
        return _keywordTrie.Contains(word);
    }
    
    /// <summary>
    /// 获取所有关键字（供外部使用，如IDE）
    /// </summary>
    public static IEnumerable<string> GetAllKeywords()
    {
        return _keywords.Concat(_typeKeywords).Concat(_arrayTypeKeywords);
    }
}


